﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using WebUtils;

namespace OAuth
{
#if PocketPC
#else
    [DebuggerDisplay("{Name}")]
#endif
    public abstract class SignatureMethod
    {
        public abstract string Name { get; }
        public abstract string CreateSignature(
            IUnsignedWebRequest pRequest, 
            IOAuthSessionParameter pSessionParameter,
            IEnumerable<UnEncodedURLParameter> pOAuthParameters);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pRequest"></param>
        /// <returns></returns>
        /// <remarks>
        /// 9.1.1.  Normalize Request Parameters
        /// 
        /// The request parameters are collected, sorted and concatenated into a normalized string:
        /// 
        ///     * Parameters in the OAuth HTTP Authorization header (Authorization Header) excluding the realm parameter.
        ///     * Parameters in the HTTP POST request body (with a content-type of application/x-www-form-urlencoded).
        ///     * HTTP GET parameters added to the URLs in the query part (as defined by [RFC3986] (Berners-Lee, T., “Uniform Resource Identifiers (URI): Generic Syntax,” .) section 3).
        /// 
        /// The oauth_signature parameter MUST be excluded.
        /// 
        /// The parameters are normalized into a single string as follows:
        /// 
        ///    1. Parameters are sorted by name, using lexicographical byte value ordering. If two or more parameters share the same name, they are sorted by their value. For example:
        /// 
        ///                           a=1, c=hi%20there, f=25, f=50, f=a, z=p, z=t
        /// 
        ///    2. Parameters are concatenated in their sorted order into a single string. For each parameter, the name is separated from the corresponding value by an ‘=’ character (ASCII code 61), even if the value is empty. Each name-value pair is separated by an ‘&’ character (ASCII code 38). For example:
        /// 
        ///                           a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t
        /// 
        /// 
        /// </remarks>
        protected string GetNormalizedRequestParameters(IUnsignedWebRequest pRequest, IEnumerable<UnEncodedURLParameter> pOAuthParameters)
        {
            // add all the parameters
            // and sorte them by key, then by value
            // then encoded
            // add to the result in the standard way
            bool isFirst = true;

            StringBuilder result = new StringBuilder();
            (from pair in (pOAuthParameters.Concat(pRequest.GetParameters).Concat(pRequest.PostParameters))
             orderby pair.Key, pair.Value
             select pair)
                .ForEach(pair => pair.Encode())
                .ForEach(pair =>
                    {
                        if (isFirst)
                            isFirst = false;
                        else
                            result.Append('&');

                        result.AppendFormat("{0}={1}", pair.Key, pair.Value);
                    });

            return result.ToString();
        }

        protected string GetNormalizedRequestUrl(string pRequestAddress)
        {
            var requestUri = new Uri(pRequestAddress);
            var normalizedUrl = new StringBuilder();
            normalizedUrl.AppendFormat("{0}://{1}", requestUri.Scheme, requestUri.Host);
            if (!((requestUri.Scheme == "http" && requestUri.Port == 80) || (requestUri.Scheme == "https" && requestUri.Port == 443)))
            {
                normalizedUrl.AppendFormat(":{0}",requestUri.Port);
            }
            normalizedUrl.Append(requestUri.AbsolutePath);

            return normalizedUrl.ToString();
        }

    }
}
